<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="renderer" content="webkit">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
    @include('common-css')
    <style>

        .input_box {
            width: 100%;
            height: 40px;
            margin-top: 15px;
            margin-bottom: 15px;
            display: flex;
            justify-content: flex-start;
            align-items: center;
        }

        .input_label {
            width: 120px;
            box-sizing: border-box;
        }

        .reviewer-table {
            margin-top: 15px;
        }

        .status-tag {
            color: #1890ff;
            border: 1px solid #91d5ff;
            border-radius: 3px;
            background: #e6f7ff;
            font-size: 12px;
            padding: 2px 3px;
        }

        .ant-table-tbody > tr > td, .ant-table-thead > tr > th {
            vertical-align: middle;
            line-height: 25px;
        }

        .search_box {
            width: 1000px;
        }

        .search_box input {
            width: 300px;
        }

        .search_box button {
            margin-left: 20px;
        }

        .search_box .ant-select {
            margin-left: 20px;
        }

        .edit-reviewer-table {
            width: 100%;
            line-height: 25px;
        }

        .edit-reviewer-table td {
            padding: 5px;
        }

        .delete-btn-a {
            color: #f5222d
        }
    </style>
</head>
<body>

<div id="app"></div>

<script id="appTemplate" type="x-template">
    <a-locale-provider :locale="antdLocale">
        <div class="container">

            @include('admin.header-tpl')

            <main>
                <div class="common_container">

                    @include('admin.aside-tpl')

                    <div class="common_content admin_common_content">

                        <div>

                            <a-button type="primary" @click="showAddReviewerDialog">添加评审专家</a-button>

                        </div>

                        <div style="display: flex; position: relative; margin-top: 10px; align-items: center;">

                            <label style="margin-right: 20px;">
                                是否参加网评
                                <a-tooltip>
                                    <template slot="title">
                                        <span>即是否已被分配给某个网评专家组</span>
                                    </template>
                                    <a-icon type="info-circle"/>
                                </a-tooltip>
                            </label>
                            <a-radio-group v-model="attendedReviewFilter">
                                <a-radio-button
                                        value="">不限(@{{ countReviewersByWhetherAttendedReview('') }})
                                </a-radio-button>
                                <a-radio-button value="参加">参加(@{{
                                    countReviewersByWhetherAttendedReview('参加') }})
                                </a-radio-button>
                                <a-radio-button value="不参加">不参加(@{{
                                    countReviewersByWhetherAttendedReview('不参加') }})
                                </a-radio-button>
                            </a-radio-group>

                            <span style="flex: 1;"></span>


                            <a-input style="width: 300px;" placeholder="搜索" v-model="searchKeyword"/>
                            <a-icon v-if="searchKeyword"
                                    style="position: absolute; top: 8px; right: 8px; color: #aaa; cursor: pointer;"
                                    type="cross"
                                    @click="searchKeyword = ''"/>
                        </div>

                        <div style="display: flex; position: relative; margin-top: 10px; align-items: center;">
                            <label style="margin-right: 20px;">
                                是否排除出网评候选专家
                                <a-tooltip>
                                    <template slot="title">
                                        <span>创建网评专家组时，被排除的专家不会出现在候选专家列表中</span>
                                    </template>
                                    <a-icon type="info-circle"/>
                                </a-tooltip>
                            </label>
                            <a-radio-group v-model="excludedFilter">
                                <a-radio-button
                                        :value="null">不限(@{{ countReviewersByIsExcluded(null) }})
                                </a-radio-button>
                                <a-radio-button :value="true">排除(@{{
                                    countReviewersByIsExcluded(true) }})
                                </a-radio-button>
                                <a-radio-button :value="false">不排除(@{{
                                    countReviewersByIsExcluded(false) }})
                                </a-radio-button>
                            </a-radio-group>
                        </div>

                        <a-table class="reviewer-table"
                                 rowKey="id"
                                 size="small"
                                 :columns="reviewerTableColumns"
                                 :dataSource="filteredReviewers"
                                 :loading="loadingPageData"
                                 :pagination="{pageSize: 10000, hideOnSinglePage: true, position: 'both', showTotal: total => `共 ${total} 项`}"
                        >

                        <span slot="prof_fields" slot-scope="text, record">
                            @{{ record.prof_fields.join('、') }}
                        </span>

                            <span slot="is_excluded" slot-scope="text, record">
                            @{{ record.is_excluded ? '排除' : '不排除' }}
                                <template v-if="record.is_excluded">
                                    <br/>
                                    <span style="margin-top: 20px; font-size: smaller; color: grey;">排除原因</span><br/>
                                    <a-input v-model="record.excluded_reason"
                                             @focus="handleExcludedReasonFocus(record)"
                                             @blur="handleExcludedReasonBlur(record)"/>
                                </template>
                        </span>

                            <span slot="password" slot-scope="text, record">
                            <span v-if="record.show_password">
                                @{{ record.password }}
                                <a href="javascript:" @click="record.show_password = false">隐藏</a>
                            </span>
                            <span v-else>
                                <a href="javascript:" @click="$set(record, 'show_password', true)">显示</a>
                            </span>
                            <a href="javascript:" @click="handleModifyReviewerPassword(record)">修改</a>
                        </span>

                            <span slot="operations" slot-scope="text, record">
                                <a @click="editReviewer(record)">编辑</a>
                                <a-popconfirm title="确认删除该评审专家？" okText="是" cancelText="否"
                                              @confirm="handleDeleteReviewer(record)">
                                    <a class="delete-btn-a" style="margin-left: 10px;">删除</a>
                                </a-popconfirm>
                                <br/>
                                <a v-if="!record.is_excluded" @click="handleExcludeReviewer(record)">排除出网评候选专家</a>
                                <a v-else @click="handleCancelExcludeReviewer(record)">恢复为网评候选专家</a>
                            </span>

                        </a-table>

                    </div>

                </div>
            </main>

            <a-modal :width="500" v-model="editReviewerDialogVisible"
                     :title="editingReviewer.id ? '修改评审专家信息' : '添加评审专家'"
                     @ok="handleSaveEditingReviewer">

                <table class="edit-reviewer-table">
                    <tr>
                        <td width="100">姓名</td>
                        <td>
                            <a-input ref="editingReviewerNameInput" v-model="editingReviewer.name"/>
                        </td>
                    </tr>
                    <tr>
                        <td>单位</td>
                        <td>
                            <a-input v-model="editingReviewer.work_org_name"/>
                        </td>
                    </tr>
                    <tr>
                        <td>职务</td>
                        <td>
                            <a-input v-model="editingReviewer.prof_title"/>
                        </td>
                    </tr>
                    <tr>
                        <td>联系方式</td>
                        <td>
                            <a-input v-model="editingReviewer.tel"/>
                        </td>
                    </tr>
                    <tr>
                        <td>专业领域</td>
                        <td>
                            <label style="display: inline-block; min-width: 150px;" v-for="option in reviewerProfFields"
                                   :key="option">
                                <input type="checkbox" v-model="editingReviewer.prof_fields" :value="option"> @{{ option
                                }}
                            </label>
                        </td>
                    </tr>
                </table>

            </a-modal>

            <a-modal :width="200" v-model="modifyReviewerPasswordDialogVisible"
                     title='修改评审专家密码'
                     @ok="handleConfirmModifyReviewerPassword">
                <span>
                    <label>新密码</label>
                    <a-input ref="reviewerNewPasswordInput" v-model="modifyReviewerPasswordModel.new_password"/>
                </span>
            </a-modal>

            <a-modal :width="200" v-model="excludeReviewerDialogVisible"
                     title='排除出网评候选专家'
                     @ok="handleConfirmExcludeReviewer">
                <span>
                    <label>排除原因</label>
                    <a-input ref="excludedReasonInput" v-model="excludeReviewerModel.excluded_reason"/>
                </span>
            </a-modal>

        </div>
    </a-locale-provider>
</script>

@include('common-js')

@include('admin.header-js')
@include('admin.aside-js')

<script>
    var queryParams = parseUrl(location.href).params;

    var reviewerTableColumns = [
        {
            width: 60,
            title: '序号',
            dataIndex: 'num'
        },
        {
            width: 100,
            title: '姓名',
            dataIndex: 'name',
        },
        {
            width: 200,
            title: '单位',
            dataIndex: 'work_org_name',
        },
        {
            width: 100,
            title: '职务',
            dataIndex: 'prof_title',
        },
        {
            width: 150,
            title: '联系方式',
            dataIndex: 'tel',
        },
        {
            width: 200,
            title: '专业领域',
            dataIndex: 'prof_fields',
            scopedSlots: {
                customRender: 'prof_fields'
            }
        },
        {
            width: 200,
            title: '是否排除出网评候选专家',
            dataIndex: 'is_excluded',
            scopedSlots: {
                customRender: 'is_excluded'
            }
        },
        {
            width: 100,
            title: '用户名',
            dataIndex: 'username',
        },
        {
            width: 100,
            title: '密码',
            dataIndex: 'password',
            scopedSlots: {
                customRender: 'password'
            }
        },
        {
            width: 150,
            title: '导入时间',
            dataIndex: 'created_at',
        },
        {
            width: 200,
            title: '操作',
            dataIndex: 'operations',
            scopedSlots: {
                customRender: 'operations'
            }
        },
    ];

    var reviewerProfFields = {!! json_encode(config('vars.reviewer_prof_fields'), JSON_UNESCAPED_UNICODE) !!}

</script>

<script>
    var app = new Vue({
        el: '#app',
        template: '#appTemplate',
        data: {
            reviewerTableColumns,
            pageData: [],
            loadingPageData: false,

            attendedReviewFilter: '',
            excludedFilter: null,
            searchKeyword: '',

            editReviewerDialogVisible: false,
            editingReviewer: {
                id: '',
                name: '',
                work_org_name: '',
                prof_title: '',
                tel: '',
                prof_fields: [],
            },

            editingExcludedReasonOldValue: '',

            modifyReviewerPasswordDialogVisible: false,
            modifyReviewerPasswordModel: {
                id: null,
                new_password: '',
            },

            excludeReviewerDialogVisible: false,
            excludeReviewerModel: {
                reviewer_id: null,
                excluded_reason: ''
            },

            reviewerProfFields,
            asideSelectedKeys: [queryParams.aside_key],
            antdLocale: antd.locales.zh_CN,
            ...AdminHeader.data,
            ...AdminAside.data,
        },
        computed: {
            filteredReviewers() {
                var reviewers = this.searchFilteredReviewers;
                if (this.attendedReviewFilter) {
                    reviewers = reviewers.filter(reviewer => {
                        var reviewerStatus = reviewer.attended_review ? '参加' : '不参加';
                        return reviewerStatus == this.attendedReviewFilter
                    })
                }
                if (this.excludedFilter !== null) {
                    reviewers = reviewers.filter(reviewer => this.excludedFilter === reviewer.is_excluded)
                }
                var num = 1;
                reviewers.forEach(reviewer => {
                    reviewer.num = num++
                });
                return reviewers
            },
            searchFilteredReviewers() {
                var reviewers;
                if (this.searchKeyword) {
                    var q = this.searchKeyword.trim();
                    reviewers = this.pageData.filter(reviewer => {
                        var text = reviewer.name + reviewer.work_org_name + reviewer.prof_title + reviewer.tel + reviewer.prof_fields;
                        return text.toLowerCase().indexOf(q) != -1
                    })
                } else {
                    reviewers = this.pageData
                }
                return reviewers
            },
        },
        beforeMount() {
            this.loadAsideDefaultOpenKeys()
        },
        mounted() {
            this.reloadPageData();
            this.reloadAsideData()
        },
        methods: {
            editReviewer(reviewer) {
                this.editingReviewer = {...reviewer};
                this.editReviewerDialogVisible = true
            },
            showAddReviewerDialog() {
                this.editingReviewer = {
                    id: '',
                    name: '',
                    work_org_name: '',
                    prof_title: '',
                    tel: '',
                    prof_fields: [],
                };
                this.editReviewerDialogVisible = true;
                setTimeout(() => this.focusNameInput(), 200)
            },
            focusNameInput() {
                this.$refs.editingReviewerNameInput.$refs.input.focus()
            },
            countReviewersByWhetherAttendedReview(status) {
                var reviewers = this.searchFilteredReviewers;
                if (status === '') {
                    return reviewers.length
                }
                var count = 0;
                reviewers.forEach(reviewer => {
                    var reviewerStatus = reviewer.attended_review ? '参加' : '不参加';
                    if (reviewerStatus === status) {
                        count += 1
                    }
                });
                return count
            },
            countReviewersByIsExcluded(isExcluded) {
                var reviewers = this.searchFilteredReviewers;
                if (isExcluded === null) {
                    return reviewers.length
                }
                var count = 0;
                reviewers.forEach(reviewer => {
                    if (isExcluded === reviewer.is_excluded) {
                        count++
                    }
                });
                return count
            },
            handleExcludedReasonFocus(reviewer) {
                this.editingExcludedReasonOldValue = reviewer.excluded_reason
            },
            handleExcludedReasonBlur(reviewer) {
                if (this.editingExcludedReasonOldValue !== reviewer.excluded_reason) {
                    axios.post('/api/db/update', {
                        model: 'ExcludedReviewer',
                        records: [{
                            id: reviewer.excluded_reviewer_record_id,
                            excluded_reason: reviewer.excluded_reason,
                        }],
                    }).then(response => {
                        if (response.data.ok) {
                            success('排除原因修改成功')
                        } else {
                            error('排除原因失败')
                        }
                    })
                }
                this.editingExcludedReasonOldValue = '';
            },
            handleSaveEditingReviewer() {
                var reviewer = this.buildReviewerInfoForSave();
                var verifyResult = this.verifyReviewerInfo(reviewer);
                if (!verifyResult.ok) {
                    let msg = '';
                    for (let [prop, errorMsg] of verifyResult.bad_props) {
                        msg += errorMsg + "\n"
                    }
                    alert(msg);
                    return
                }
                reviewer.prof_fields = reviewer.prof_fields.join(',');
                if (this.editingReviewer.id) {
                    this.updateReviewer(reviewer)
                } else {
                    this.createReviewer(reviewer)
                }
                this.editReviewerDialogVisible = false
            },

            handleDeleteReviewer(reviewer) {
                axios.post('/api/db/delete', {
                    model: 'User',
                    record_ids: [reviewer.id]
                }).then(res => {
                    if (res.data.ok) {
                        success('删除评审专家成功');
                        var i = 0;
                        while (i < this.pageData.length) {
                            if (this.pageData[i].id === reviewer.id) {
                                this.pageData.splice(i, 1);
                                while (i < this.pageData.length) {
                                    this.pageData[i].num--;
                                    i++
                                }
                                break;
                            }
                            i++
                        }
                    } else {
                        error('删除评审专家失败')
                    }
                })
            },

            buildReviewerInfoForSave() {
                var result = {};
                var props = ['id', 'name', 'work_org_name', 'prof_title', 'tel', 'prof_fields'];
                for (var prop of props) {
                    var value = this.editingReviewer[prop];
                    if (typeof (value) === 'string') {
                        value = value.trim()
                    }
                    result[prop] = value
                }
                return result
            },

            verifyReviewerInfo(reviewer) {
                var bad_props = new Map();
                var props = new Map([['name', '姓名'], ['work_org_name', '单位'], ['prof_title', '职务'], ['tel', '联系方式'], ['prof_fields', '评审专业']]);
                var patternPerProp = new Map([
                    ['name', {pattern: /^\S{2,30}$/, desc: '长度为2-30，不能包含空白字符'}],
                    ['work_org_name', {pattern: /^\S{4,80}$/, desc: '长度为4-80，不能包含空白字符'}],
                    ['prof_title', {pattern: /^\S{2,20}$/, desc: '长度为2-20，不能包含空白字符'}],
                    ['tel', {pattern: /^\d{11}$/, desc: '长度为11，只能包含数字'}],
                    ['prof_fields', {pattern: null, desc: ''}],
                ]);
                for (var [prop, displayName] of props) {
                    var quotedDisplayName = `『${displayName}』`;
                    var value = reviewer[prop];
                    if (value === null || (typeof (value) === 'string' && value.length === 0) || (value instanceof Array && value.length === 0)) {
                        bad_props.set(prop, `${quotedDisplayName}不能为空`);
                        continue
                    }
                    var pattern = patternPerProp.get(prop).pattern;
                    if (pattern && !pattern.test(value)) {
                        bad_props.set(prop, quotedDisplayName + patternPerProp.get(prop).desc)
                    }
                }
                return {
                    'ok': bad_props.size === 0,
                    bad_props
                }
            },

            createReviewer(reviewer) {
                axios.post('/api/admin/create-reviewer', {
                    reviewer
                }).then(res => {
                    if (res.data.ok) {
                        success('添加评审专家成功');
                        this.pageData.unshift(res.data.reviewer);
                        this.pageData.forEach((reviewer, index) => reviewer.num = index + 1)
                    } else {
                        error(('添加评审专家失败'))
                    }
                    this.editReviewerDialogVisible = false
                })
            },

            updateReviewer(reviewer) {
                const updated_at = moment().format('Y-MM-DD HH:mm:ss');
                axios.post('/api/db/update', {
                    model: 'User',
                    records: [
                        {
                            ...reviewer,
                            updated_at,
                        }
                    ]
                }).then(res => {
                    if (res.data.ok) {
                        success('修改评审专家信息成功');
                        for (var i = 0; i < this.pageData.length; i++) {
                            var curReviewer = this.pageData[i];
                            if (curReviewer.id === reviewer.id) {
                                for (var key in reviewer) {
                                    if (!reviewer.hasOwnProperty(key)) {
                                        continue
                                    }
                                    var value = reviewer[key];
                                    if (key === 'prof_fields') {
                                        value = value.split(',')
                                    }
                                    curReviewer[key] = value;
                                }
                                this.$set(this.pageData, i, curReviewer);
                                break
                            }
                        }
                    } else {
                        error(('修改评审专家信息失败'))
                    }
                    this.editReviewerDialogVisible = false
                })
            },

            handleModifyReviewerPassword(reviewer) {
                this.modifyReviewerPasswordModel = {
                    'id': reviewer.id,
                    'new_password': '',
                };
                this.modifyReviewerPasswordDialogVisible = true;
                setTimeout(() => this.$refs.reviewerNewPasswordInput.$refs.input.focus(), 200)
            },

            handleConfirmModifyReviewerPassword() {
                var reviewer_id = this.modifyReviewerPasswordModel.id;
                var new_password = this.modifyReviewerPasswordModel.new_password;
                var pattern = /^[_a-zA-Z0-9]{6,20}$/;
                if (!pattern.test(new_password)) {
                    alert('密码长度为6-20，只能包括字母、数字或下划线(_)');
                    return
                }
                axios.post('/api/db/update', {
                    'model': 'User',
                    'records': [{id: reviewer_id, password: new_password}]
                }).then(response => {
                    if (response.data.ok) {
                        success('修改评审专家密码成功');
                        for (var i = 0; i < this.pageData.length; i++) {
                            var curReviewer = this.pageData[i];
                            if (curReviewer.id === reviewer_id) {
                                this.$set(curReviewer, 'password', new_password);
                                break
                            }
                        }
                    } else {
                        error('修改评审专家密码失败')
                    }
                    this.modifyReviewerPasswordDialogVisible = false
                })
            },

            handleExcludeReviewer(reviewer) {
                this.excludeReviewerModel = {
                    reviewer_id: reviewer.id,
                    excluded_reason: '',
                }
                this.excludeReviewerDialogVisible = true
            },

            handleConfirmExcludeReviewer() {
                axios.post('/api/db/create', {
                    'model': 'ExcludedReviewer',
                    'records': [this.excludeReviewerModel]
                }).then(response => {
                    if (response.data.ok) {
                        success('排除出网评候选专家成功');
                        this.reloadPageData()
                    } else {
                        error('排除出网评候选专家失败')
                    }
                    this.excludeReviewerDialogVisible = false
                })
            },

            handleCancelExcludeReviewer(reviewer) {
                axios.post('/api/db/delete', {
                    'model': 'ExcludedReviewer',
                    'record_ids': [reviewer.excluded_reviewer_record_id]
                }).then(response => {
                    if (response.data.ok) {
                        success('恢复为网评候选专家成功');
                        this.reloadPageData()
                    } else {
                        error('恢复为网评候选专家失败')
                    }
                })
            },

            reloadPageData() {
                this.loadingPageData = true;
                axios.get('/api/admin/get-reviewers').then(response => {
                    this.pageData = response.data;
                    this.loadingPageData = false
                })
            },
            ...AdminHeader.methods,
            ...AdminAside.methods,
        }
    })
</script>

</body>
</html>